home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-03-22 | 58.2 KB | 1,831 lines |
- // copyright 1993 Michael B. Johnson; some portions copyright 1994, MIT
- // see COPYRIGHT for reuse legalities
- //
-
- #import "WWTCLKit.h"
-
- #import "EveCommand.h"
- #import "RIBCommand.h"
- #import "RIBTranslate.h"
- #import "WWEveParser.h"
- #import "WW3DShape.h"
- #import "WW3DWell.h"
- #import "Protocol_WWAnimatable.h"
- #import "WW3DAttributeState.h"
- #import "usefulWW3DFunctions.h"
-
- #import "WWSceneClock.h" // has the sceneClock protocol - formalize this!
-
- #import <string.h>
-
- @interface WW3DShape(Private)
- - updateEveCmd:(EveCommand *)eveCmd;
- @end
-
- // this block was put in for Ian - wave has no idea what it does...
- @implementation WW3DShape(Private)
- static const char *RIBTranslateCmd = "Translate";
- static const char *RIBTranslateLimitation = "Currently require all the Translate arguments appearing in an EveCmd to be traced variables.";
-
- - updateEveCmd:(EveCommand *)eveCmd
- {
- WWTCLClosedCmd *tclClosedCmd;
- WWTCLVarTrace *trace;
- char transComp[100];
- List *tracedVars;
- const char *cmd;
- int nVars;
-
- tclClosedCmd = [eveCmd command];
- cmd = [tclClosedCmd cmd];
- if (strstr(cmd, RIBTranslateCmd)) {
- tracedVars = [tclClosedCmd tracedVars];
- nVars = [tracedVars count];
- if (nVars < 3) {
- NXLogError(RIBTranslateLimitation);
- return self;
- }
- #if 0
- trace = [tracedVars objectAt:0];
- sprintf(transComp, "%f", transform[3][0]);
- [interp setVar:[trace varName] toValue:transComp];
- trace = [tracedVars objectAt:1];
- sprintf(transComp, "%f", transform[3][1]);
- [interp setVar:[trace varName] toValue:transComp];
- trace = [tracedVars objectAt:2];
- sprintf(transComp, "%f", transform[3][2]);
- [interp setVar:[trace varName] toValue:transComp];
- #endif
- strcpy(transComp, "0.0");
- trace = [tracedVars objectAt:0];
- [interp setVar:(char *)[trace varName] toValue:transComp];
- trace = [tracedVars objectAt:1];
- [interp setVar:(char *)[trace varName] toValue:transComp];
- trace = [tracedVars objectAt:2];
- [interp setVar:(char *)[trace varName] toValue:transComp];
- }
- return self;
- }
- @end
-
- @implementation WW3DShape
-
-
- + initialize { [WW3DShape setVersion:2]; return self; }
-
- - init
- {
- [super init];
-
- ribCommandList = [[List alloc] init];
- childList = [[List alloc] init];
- siblingList = [[List alloc] init];
-
- unselectedColor[0] = 0.9; unselectedColor[1] = 0.9; unselectedColor[2] = 0.9;
-
- selectedColor[0] = 0.9; selectedColor[1] = 0.9; selectedColor[2] = 0.0;
-
- xColor[0] = 1.0; xColor[1] = 0.0; xColor[2] = 0.0;
- xExtent = 0.0;
-
- yColor[0] = 0.0; yColor[1] = 1.0; yColor[2] = 0.0;
- yExtent = 0.0;
-
- zColor[0] = 0.0; zColor[1] = 0.0; zColor[2] = 1.0;
- zExtent = 0.0;
-
- selected = NO;
- drawOrigin = NO;
- [self setSelectable:YES];
-
- shadingGroup = NULL;
- materialGroup = NULL;
- geometryGroup = NULL;
-
- pathSeparator = '/';
-
- dirtyBoundingBox = YES;
- dirtyBases = YES;
-
- interp = nil;
- sceneClock = nil;
-
- hasEveCmd = NO;
-
- originTesselationVector[0] = originTesselationVector[1] = 4.0;
-
- return self;
- }
-
- - initWithInterp:newInterp andSceneClock:newSceneClock
- {
- [self init];
- interp = newInterp;
- sceneClock = newSceneClock;
-
- return self;
- }
-
- // need to put awake in here...
-
- - awake
- {
- [super awake];
- originTesselationVector[0] = originTesselationVector[1] = 4.0;
- /*
- NXLogError("in awake, WW3DShape <%s> boundingBox is (%f, %f) (%f, %f) (%f, %f)\n",
- [self shapeName],
- boundingBox[0], boundingBox[1], boundingBox[2], boundingBox[3], boundingBox[4], boundingBox[4]);
- */
- return self;
- }
-
- - free
- {
- //NXLogError("WW3DShape %s (%p) %p being free'ed\n", [self shapeName], [self shapeName], self);
- [[ribCommandList freeObjects] free];
-
- // we assume super will send the free message to our descendants...
- //NXLogError("childList %p being free'ed\n", childList);
- [childList free];
- //NXLogError("siblingList %p being free'ed\n", siblingList);
- [siblingList free];
-
- return [super free];
- }
-
- - copyFromZone:(NXZone *)zone
- {
- id newCopy = [super copyFromZone:zone];
-
- NXLogError("WARNING: copyFromZone: incompletely implemented for %s", [[self class] name]);
-
- return newCopy;
- }
-
- // this method was put in for Ian - wave has no idea what it does...
- - performUpdateForInteraction:(WW3DCamera *)camera
- /*
- * For now, we hit the simplicity trail...
- * We enumerate the ribCommandList; for each EveCommand
- * encountered, we determine if it conforms to the WWRenderable
- * protocol. If it does, and it affects the transformation
- * matrix of the shape, then we go ahead and write the various
- * (traced) variables for the RIBCommand.
- */
- {
- if (hasEveCmd) {
- WWEveParser *eveParser;
- int count, i;
-
- eveParser = [[camera delegate] parser];
- count = [ribCommandList count];
- for (i = 0; i < count; i++) {
- id aCmd = [ribCommandList objectAt:i];
- if ([aCmd isKindOf:[EveCommand class]]) {
- [self updateEveCmd:aCmd];
- }
- }
- }
- return self;
- }
-
- - tclInterp { return interp; }
-
- - sceneClock { return sceneClock; }
-
-
- - transformCTM:(WW3DAttributeState *)attributeState startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- { NXLogError("why are you calling transformCTM:startingAt:endingAt: for WW3DShape <%s>?\n", [self shapeName]);
- return self;
- }
-
- - (BOOL)isSelectable { return YES; } // This is a N3DKit thing, not mine
-
- - (BOOL)isLerpable { return NO; }
- - lerpWith:b by:(float)uValue { return self; }
- - lerpSelfWith:b by:(float)uValue { return self; }
-
- - (BOOL)isMotionBlurrable { return YES; } // this isn't strictly true, ya know...
-
- - (BOOL)isCompoundCommand { return YES; } // this isn't strictly true, ya know...
-
- - (BOOL)hasBoundingBox { return YES; } // this isn't strictly true, ya know...
-
- - (float)lastSampleIsAt
- {
- float oldestSample = 0.0, newSample;
- int i, howMany = [ribCommandList count];
-
-
- for (i = 0; i < howMany; i++)
- { newSample = [(id <WWRenderable>)[ribCommandList objectAt:i] lastSampleIsAt];
- if (newSample > oldestSample)
- { oldestSample = newSample;
- }
- }
-
- newSample = [descendant lastSampleIsAt];
- if (newSample > oldestSample)
- { oldestSample = newSample;
- }
-
- newSample = [nextPeer lastSampleIsAt];
- if (newSample > oldestSample)
- { oldestSample = newSample;
- }
-
- return oldestSample;
- }
-
- - (unsigned long int)maxSampleBandwidth;
- {
- unsigned long int maxSampleBandwidth = 50; //WAVE FIX ME
- int i, howMany = [ribCommandList count];
-
-
- for (i = 0; i < howMany; i++)
- { maxSampleBandwidth += [(id <WWRenderable>)[ribCommandList objectAt:i] maxSampleBandwidth];
- }
-
- maxSampleBandwidth += [descendant maxSampleBandwidth];
- maxSampleBandwidth += [nextPeer maxSampleBandwidth];
-
- return maxSampleBandwidth;
- }
-
-
- - (BOOL)isMoot
- {
- return NO;
- }
-
- - (BOOL)isMootStartingAt:(float)startTime endingAt:(float)endTime { return [self isMoot]; }
-
- - (BOOL)theSameAs:otherRIBCommand
- {
- return NO;
- }
-
- - (BOOL)similarTo:otherRIBCommand
- {
- if ([self class] != [otherRIBCommand class])
- { return NO;
- }
- return YES;
- }
-
-
- - setShader_:newShader { return [super setShader:newShader]; }
-
- - removeSurfaceShader:sender
- {
- if (surfaceShader)
- { [surfaceShader free];
- }
- surfaceShader = nil;
- return self;
- }
-
- - removeDisplacementShader:sender
- {
- if (displacementShader)
- { [displacementShader free];
- }
- displacementShader = nil;
- return self;
- }
-
-
- - setBoundingBox:(RtBound *)newBoundingBox { return nil; }
-
- // this is really a private method when some part of a shape (i.e. one
- // of it's rib commands) does something that it knows probably
- //invalidates the entire shape's bounding box.
- - setBoundingBoxDirty { dirtyBoundingBox = YES; return self; }
-
-
- // here's the deal. Given a bounding box, we're going to transform that
- // by the given transformation matrix. Since this effects the extent
- // of the object, we have to transform all 8 points of the bounding box.
- // After transforming them, we the redetermine the min and max of things
- - determineBound:(RtBound *)newBB givenBound:(RtBound *)aBB andCTM:(RtMatrix)aCTM
- {
- RtPoint bboxPoints[8], bboxPointsTransformed[8];
- int i;
-
-
- N3D_XComp(bboxPoints[0]) = (*aBB)[0];
- N3D_YComp(bboxPoints[0]) = (*aBB)[2];
- N3D_ZComp(bboxPoints[0]) = (*aBB)[4];
-
- N3D_XComp(bboxPoints[1]) = (*aBB)[1];
- N3D_YComp(bboxPoints[1]) = (*aBB)[2];
- N3D_ZComp(bboxPoints[1]) = (*aBB)[4];
-
- N3D_XComp(bboxPoints[2]) = (*aBB)[0];
- N3D_YComp(bboxPoints[2]) = (*aBB)[3];
- N3D_ZComp(bboxPoints[2]) = (*aBB)[4];
-
- N3D_XComp(bboxPoints[3]) = (*aBB)[1];
- N3D_YComp(bboxPoints[3]) = (*aBB)[3];
- N3D_ZComp(bboxPoints[3]) = (*aBB)[4];
-
- N3D_XComp(bboxPoints[4]) = (*aBB)[0];
- N3D_YComp(bboxPoints[4]) = (*aBB)[2];
- N3D_ZComp(bboxPoints[4]) = (*aBB)[5];
-
- N3D_XComp(bboxPoints[5]) = (*aBB)[1];
- N3D_YComp(bboxPoints[5]) = (*aBB)[2];
- N3D_ZComp(bboxPoints[5]) = (*aBB)[5];
-
- N3D_XComp(bboxPoints[6]) = (*aBB)[0];
- N3D_YComp(bboxPoints[6]) = (*aBB)[3];
- N3D_ZComp(bboxPoints[6]) = (*aBB)[5];
-
- N3D_XComp(bboxPoints[7]) = (*aBB)[1];
- N3D_YComp(bboxPoints[7]) = (*aBB)[3];
- N3D_ZComp(bboxPoints[7]) = (*aBB)[5];
-
- N3DMult3DPoints(bboxPoints, 8, aCTM, bboxPointsTransformed);
-
- // start off setting newBB to be the first point
- (*newBB)[0] = (*newBB)[1] = N3D_XComp(bboxPointsTransformed[0]);
- (*newBB)[2] = (*newBB)[3] = N3D_YComp(bboxPointsTransformed[0]);
- (*newBB)[4] = (*newBB)[5] = N3D_ZComp(bboxPointsTransformed[0]);
-
- for (i = 1; i < 8; i++)
- { //// X
- if ((*newBB)[0] > N3D_XComp(bboxPointsTransformed[i]))
- { (*newBB)[0] = N3D_XComp(bboxPointsTransformed[i]);
- }
- if ((*newBB)[1] < N3D_XComp(bboxPointsTransformed[i]))
- { (*newBB)[1] = N3D_XComp(bboxPointsTransformed[i]);
- }
- //// Y
- if ((*newBB)[2] > N3D_YComp(bboxPointsTransformed[i]))
- { (*newBB)[2] = N3D_YComp(bboxPointsTransformed[i]);
- }
- if ((*newBB)[3] < N3D_YComp(bboxPointsTransformed[i]))
- { (*newBB)[3] = N3D_YComp(bboxPointsTransformed[i]);
- }
- //// Z
- if ((*newBB)[4] > N3D_ZComp(bboxPointsTransformed[i]))
- { (*newBB)[4] = N3D_ZComp(bboxPointsTransformed[i]);
- }
- if ((*newBB)[5] < N3D_ZComp(bboxPointsTransformed[i]))
- { (*newBB)[5] = N3D_ZComp(bboxPointsTransformed[i]);
- }
- }
-
- return self;
- }
-
-
- - (BOOL)pushesOrPopsCTM { return NO; }
- - (BOOL)pushesCTM { return NO; }
- - (BOOL)popsCTM { return NO; }
-
- // the asumption here is that cmd (i - 1) pushes the CTM, so we want to
- // grovel over the remaining commands until we find one that pops the CTM
- // it should recurse
- // the starting condition
- - (int)findBoundingBoxFromRIBCommands:(int)startingIndex using:attributeState startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- RtBound tmpBoundingBox;
- RtMatrix tmpCTM;
- int i = startingIndex,
- incr,
- howMany = [ribCommandList count];
- id cmd;
- id newAttributeState;
-
-
- // first we need to find a bounding box to start with
- while (i < howMany)
- { cmd = [ribCommandList objectAt:i];
-
- // if the cmd pops the attribute stack, we're done.
- // we return how many commands we've gone through in our time here
- if ([cmd popsCTM])
- { i++;
- return (i - startingIndex);
- }
-
- if ([cmd pushesCTM]) // here we go again...
- { newAttributeState = [[WW3DAttributeState alloc] init];
- i++;
- incr = [self findBoundingBoxFromRIBCommands:i using:newAttributeState startingAt:shutterOpenTime endingAt:shutterCloseTime];
- // we now need to merge this sub-attribute block into our current one
- if ([newAttributeState hasBoundingBox])
- { // This means that the bounding box in newAttributeState needs to be
- // transformed by the ctm of attributeState, and then we need to
- // "grow" to the current bound with that tranformed sub-bound.
-
- [attributeState getTransformMatrix:tmpCTM];
- WW3DDetermineBoundGivenBoundAndCTM(&tmpBoundingBox, [newAttributeState boundingBox], tmpCTM);
- [attributeState growBoundingBox:&tmpBoundingBox];
- }
- else
- { //NXLogError("warning: WW3DShape <%s> has a moot set of commands at indices %d to %d\n", [self shapeName], (i - 1), (i + incr - 1));
- //NXLogError("\tif there was a LightSource or AreaLight source in there, you can ignore this warning, though...\n");
- }
- i += incr;
- }
- else
- { [cmd transformCTM:attributeState startingAt:shutterOpenTime endingAt:shutterCloseTime];
- i++;
- }
-
- if ([cmd hasBoundingBox])
- { // great! we grow the bound of the current attribute state
- [attributeState growBoundingBox:[cmd boundingBoxStartingAt:shutterOpenTime endingAt:shutterCloseTime]];
- }
-
- }
- return (i - startingIndex);
- }
-
-
-
- - calculateBoundingBoxStartingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- RtBound tmpBoundingBox;
- RtMatrix childMatrix, tmpCTM;
- int i, startingChildIndex = 0, howManyKids;
- id child, kids, newAttributeState;
-
-
- //NXLogError("calculating bbox for shape <%s>\n", [self shapeName]);
-
- // this one is tricky. we'll need to be smart about this...
-
- // basically, each RIBCommand has it's own bounding box. We ask
- // each one in turn for it's boundingBox, and use that to build up ours.
- // Remember that each command is smart enough to know if any of it's
- // parameters have changed, but we need to be smart to realize if we have
- // rotated/translated/scaled. Recall that for scaling and translating we
- // can just add that to the boundingBox without asking everyone to recalculate,
- // but rotating mucks up everything.
-
- // so we need to transform these points against our 4x4, right?
- // Does the 3DKit take care of that for us? Hmmm...
-
- // Actually, I don't think we need to cat our 4x4 against it,
- // although I'm still unclear... Anyway, what we really want to do is
- // grovel over our ribCommandList and, to each object which answers YES
- // to hasBoundingBox we send the appropriate msg to get the bounding box
- // and compare it against ours.
-
- // actually, one more difficulty is that even though we might not
- // have any geometry (i.e. have any RIBCommands that respond
- // positively to -hasBoundingBox), we still might have some commands
- // transform the boundingBox, ie. do more than concatenate an identity
- // matrix against the matrix passed into -transform:.
-
- // what if you had 3 commands, the first two of which didn't have bounding boxes.
- // first time through, i == 1 at the end
- // next time, i == 2 at the end
- // final time through, i doesn't get incremented, but we are done
- // actually, it's more complicated than that.
- // some of these RIBCommands might not have a bounding box, but they do transform the CTM
- // also, you might have some transformational commands, then some geometry, then more
- // transformational commands, then geometry, then some more transformational... These
- // would all effect the children shapes in toto, but would also be affecting the
- // bounding box of the various geometry commands.
- // urgh...
-
- // It's not really so bad. Everything is taking place in the space of this shape, which
- // means that this shape's transformation matrix isn't consulted. We start off with
- // the identity matrix, and transform a tmp CTM (current transformation matrix) as we
- // move through the commands.
-
- // Actually, it's a bit trickier than you might think. The problem
- // is that although we have no fear of dropping down into a child until
- // we get to the list of kids, we just might hit a RIBAttributeBegin,
- // RIBTransformBegin, or RIBSolidBegin object, which would have the same effect
- // So, it looks like we need to extend the WWRenderable protocol to let us know
- // if the object pushes or pops the transformation stack. We'll need to recurse
- // down the transformation tree, building up the CTM, and transforming any bounding
- // box we find. We start off when the command pushes the stack. We cons up a new
- // CTM and set it to the Identity matrix. We then start walking down the commands,
- // first asking the command if it has a boundingBox. If it does, we set our bound
- // to it, and then transform the points in the bound by our CTM. We
- // then continue walking down the tree, asking each command if has a
- // bounding box, and if does, transforming that box by the CTM, and then
- // comparing it to our current bound, and growing it accordingly. If the
- // command doesn't have a bound, we just transform our CTM and our
- // current bound by it. We continue this until we get find a command
- // which pops the attribute stack. If, along the way, we hit a command which
- // actually pushes the stack, we need to recurse down and call this routine again.
- // The routine should be passed, and return, the id of a list of WW3DAttributeState
- // objects, which have a bounding box, a CTM, etc. in them.
-
- newAttributeState = [[WW3DAttributeState alloc] init];
- i = [self findBoundingBoxFromRIBCommands:0 using:newAttributeState startingAt:shutterOpenTime endingAt:shutterCloseTime];
- if (i != [ribCommandList count])
- { NXLogError("warning: shape <%s> has an unbalanced attribute delimiter at command %d (expected %d)\n",
- [self shapeName], i, [ribCommandList count]);
- return nil;
- }
-
- [newAttributeState getTransformMatrix:tmpCTM];
-
- if (![newAttributeState hasBoundingBox]) // this Shape has no real geometry in it, but it might have kids...
- { // we still need some approximation to start off with for this shape's bounding box.
- // to get it, we use our first child's bounding box.
- // if we don't have any kids, we just return.
- kids = [self children];
- if ([kids count] < 1)
- { dirtyBoundingBox = NO;
- return self;
- }
-
- // note that it's fair to assume that if we have children, each one has a bounding
- // box. If it didn't have a bounding box, that would mean it was a leaf node of
- // the tree without any geometry, which means we've got a moot node.
- child = [kids objectAt:0];
-
- // now, we can't just copy this bounding box, because it needs to
- // be transformed by the 4x4 that represents the transformation from this
- // shape to the child, i.e. it's 4x4.
- N3D_CopyBound(*([child boundingBoxStartingAt:shutterOpenTime endingAt:shutterCloseTime]), tmpBoundingBox);
-
- WW3DDetermineBoundGivenBoundAndCTM(&boundingBox, &tmpBoundingBox, tmpCTM);
-
- startingChildIndex = 1;
- }
- else
- { N3D_CopyBound(*([newAttributeState boundingBox]), boundingBox);
- }
-
- // at this point, we only have a bounding box for the geometry
- // associated with this shape's geometry. We now need to recurse down
- // our children, asking each to calculate it's bounding box. We then
- // compare that bounding box with our own, and update ours accordingly.
- // note that if we didn't have any geometry in this shape, we've already
- // looked at the boundingBox of our first child, and set our boundingBox
- // to that, so startingChildIndex has been incremented to 1, so we
- // don't waste time redoing that.
- kids = [self children];
- howManyKids = [kids count];
- for (i = startingChildIndex; i < howManyKids; i++)
- { child = [kids objectAt:i];
- N3D_CopyBound(*([child boundingBoxStartingAt:shutterOpenTime endingAt:shutterCloseTime]), tmpBoundingBox);
-
- // the boundingBox that we get from the child should already be transformed
- // correctly, right? Or do we also need to concat the child's transform
- // onto it? Yes, I think we do need to. We get the bound, convert it to points,
- // transform it against the child's CTM, then multiply *that* by the
- // tmpCTM (which takes into account transformational RIBCommands in this
- // shape, which will get executed before the child shape, and then
- // convert those points back to a bound. We can check that against
- // the current bound.
-
- // we need to transform that bounding box to reflect the transformational
- // commands that precede it in this shape's ribCommandList
- [child getTransformMatrix:childMatrix];
- WW3DDetermineBoundGivenBoundAndCTM(&tmpBoundingBox, &tmpBoundingBox, childMatrix);
- WW3DDetermineBoundGivenBoundAndCTM(&tmpBoundingBox, &tmpBoundingBox, tmpCTM);
-
- // now we should all be in the same space; compare against current boundingBox
- //// X
- if (tmpBoundingBox[0] < boundingBox[0])
- { boundingBox[0] = tmpBoundingBox[0];
- }
- if (tmpBoundingBox[1] > boundingBox[1])
- { boundingBox[1] = tmpBoundingBox[1];
- }
- //// Y
- if (tmpBoundingBox[2] < boundingBox[2])
- { boundingBox[2] = tmpBoundingBox[2];
- }
- if (tmpBoundingBox[3] > boundingBox[3])
- { boundingBox[3] = tmpBoundingBox[3];
- }
- //// Z
- if (tmpBoundingBox[4] < boundingBox[4])
- { boundingBox[4] = tmpBoundingBox[4];
- }
- if (tmpBoundingBox[5] > boundingBox[5])
- { boundingBox[5] = tmpBoundingBox[5];
- }
- }
-
- xExtent = boundingBox[1] - boundingBox[0];
- yExtent = boundingBox[3] - boundingBox[2];
- zExtent = boundingBox[5] - boundingBox[4];
-
- //fprintf(stderr, "shape %s has extents of (%f, %f, %f)\n", [self shapeName], xExtent, yExtent, zExtent);
- //fprintf(stderr, "\t bbox : X (%f, %f)\n", boundingBox[0], boundingBox[1]);
- //fprintf(stderr, "\t : Y (%f, %f)\n", boundingBox[2], boundingBox[3]);
- //fprintf(stderr, "\t : Z (%f, %f)\n", boundingBox[4], boundingBox[5]);
-
- dirtyBoundingBox = NO;
-
- return self;
- }
-
- #define X_AXIS 1.0, 0.0, 0.0
- #define Y_AXIS 0.0, 1.0, 0.0
- #define Z_AXIS 0.0, 0.0, 1.0
- #define wwMax(a,b) (((a)>(b))?(a):(b))
- #define wwMin(a,b) (((a)>(b))?(b):(a))
-
- - drawOriginStartingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- { if (drawOrigin)
- { [self boundingBoxStartingAt:shutterOpenTime endingAt:shutterCloseTime]; // call this to make sure that my boundingBox is current...
- RiAttributeBegin();
- RiGeometricApproximation(RI_TESSELATION, RI_PARAMETRIC, originTesselationVector, RI_NULL);
-
- // draw along Z axis
- RiColor(zColor);
- if (wwMin(xExtent, yExtent) == 0.0)
- { if ((boundingBox[4] < 0.0) && (boundingBox[5] < 0.0))
- { RiCylinder((0.01 * (wwMax(xExtent, yExtent))),
- boundingBox[4], 0.0,
- 360.0, RI_NULL);
- }
- else
- { RiCylinder((0.01 * (wwMax(xExtent, yExtent))),
- wwMin(0.0, boundingBox[4]), boundingBox[5],
- 360.0, RI_NULL);
- }
- }
- else
- { if ((boundingBox[4] < 0.0) && (boundingBox[5] < 0.0))
- { RiCylinder((0.01 * (wwMin(xExtent, yExtent))),
- boundingBox[4], 0.0,
- 360.0, RI_NULL);
- }
- else
- { RiCylinder((0.01 * (wwMin(xExtent, yExtent))),
- wwMin(0.0, boundingBox[4]), boundingBox[5],
- 360.0, RI_NULL);
- }
- }
-
- // rotate about X -90 degrees to be pointing along the Y axis
- RiRotate(-90, X_AXIS);
- RiColor(yColor);
- if (wwMin(xExtent, zExtent) == 0.0)
- { if ((boundingBox[2] < 0.0) && (boundingBox[3] < 0.0))
- { RiCylinder((0.01 * (wwMax(xExtent, zExtent))),
- boundingBox[2], 0.0,
- 360.0, RI_NULL);
- }
- else
- { RiCylinder((0.01 * (wwMax(xExtent, zExtent))),
- wwMin(0.0, boundingBox[2]), boundingBox[3],
- 360.0, RI_NULL);
- }
- }
- else
- { if ((boundingBox[2] < 0.0) && (boundingBox[3] < 0.0))
- { RiCylinder((0.01 * (wwMin(xExtent, zExtent))),
- boundingBox[2], 0.0,
- 360.0, RI_NULL);
- }
- else
- { RiCylinder((0.01 * (wwMin(xExtent, zExtent))),
- wwMin(0.0, boundingBox[2]), boundingBox[3],
- 360.0, RI_NULL);
- }
- }
-
- // rotate about Y 90 degrees to be pointing along the X axis
- RiRotate(90, Y_AXIS);
- RiColor(xColor);
- if (wwMin(yExtent, zExtent) == 0.0)
- { if ((boundingBox[0] < 0.0) && (boundingBox[1] < 0.0))
- { RiCylinder((0.01 * (wwMax(yExtent, zExtent))),
- boundingBox[0], 0.0,
- 360.0, RI_NULL);
- }
- else
- { RiCylinder((0.01 * (wwMax(yExtent, zExtent))),
- wwMin(0.0, boundingBox[0]), boundingBox[1],
- 360.0, RI_NULL);
- }
- }
- else
- { if ((boundingBox[0] < 0.0) && (boundingBox[1] < 0.0))
- { RiCylinder((0.01 * (wwMin(yExtent, zExtent))),
- boundingBox[0], 0.0,
- 360.0, RI_NULL);
- }
- else
- { RiCylinder((0.01 * (wwMin(yExtent, zExtent))),
- wwMin(0.0, boundingBox[0]), boundingBox[1],
- 360.0, RI_NULL);
- }
- }
- RiAttributeEnd();
- }
- if (selected)
- { RiColor(selectedColor);
- }
- return self;
- }
-
-
- - renderMaps:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime usingStream:(NXStream *)ns
- {
- int i, howMany = [ribCommandList count];
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[ribCommandList objectAt:i] renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
- }
- [descendant renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
- [nextPeer renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
-
- return self;
- }
-
-
- - renderMaps:(WW3DCamera *)camera usingStream:(NXStream *)ns
- {
- int i, howMany = [ribCommandList count];
- RtFloat shutterOpenTime = [camera shutterOpenTime],
- shutterCloseTime = [camera shutterCloseTime];
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWAnimatable>)[ribCommandList objectAt:i] renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
- }
- [descendant renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
- [nextPeer renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime usingStream:ns];
-
- return self;
- }
-
-
-
- - renderMaps:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- int i, howMany = [ribCommandList count];
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[ribCommandList objectAt:i] renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
- [descendant renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- [nextPeer renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
-
- return self;
- }
-
-
- - renderMaps:(WW3DCamera *)camera
- {
- int i, howMany = [ribCommandList count];
- RtFloat shutterOpenTime = [camera shutterOpenTime],
- shutterCloseTime = [camera shutterCloseTime];
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWAnimatable>)[ribCommandList objectAt:i] renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
- [descendant renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- [nextPeer renderMaps:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
-
- return self;
- }
-
-
-
- - renderSelf:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- int i, howMany = [ribCommandList count];
- id <WWRenderable> obj;
-
-
- if ([self doesDrawAsBox])
- { return self;
- }
-
- // for the origin, we want cylinders the length of the bounding box
- // I could see wanting to do this only on-screen, but sometimes for real...
- if (NXDrawingStatus == NX_DRAWING)
- { [self drawOriginStartingAt:shutterOpenTime endingAt:shutterCloseTime];
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[ribCommandList objectAt:i] renderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
- }
- else
- { for (i = 0; i < howMany; i++) // do the moot check
- { obj = (id <WWRenderable>)[ribCommandList objectAt:i];
- if (![obj isMoot])
- { [obj renderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
- }
- }
- return self;
- }
-
-
- - renderSelf:(WW3DCamera *)camera
- {
- RtFloat shutterOpenTime = [camera shutterOpenTime],
- shutterCloseTime = [camera shutterCloseTime];
-
-
- return [self renderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
-
- // I don't like the way NeXT defines this; should recurse down
- - setDrawAsBox:(BOOL)flag
- {
- int i, howMany;
- id kids;
-
-
- [super setDrawAsBox:flag];
- kids = [self children];
- howMany = [kids count];
- for (i = 0; i < howMany; i++)
- { [[kids objectAt:i] setDrawAsBox:flag];
- }
-
- return self;
- }
-
- - renderSelfAsBox:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- int i, howMany = [ribCommandList count];
- RtInt nPolys = 6;
- RtInt nVerts[6] = {4, 4, 4, 4, 4, 4 };
- RtInt verts[24] = {3, 2, 6, 7,
- 2, 1, 5, 6,
- 1, 0, 4, 5,
- 0, 3, 7, 4,
- 7, 6, 5, 4,
- 0, 1, 2, 3};
- RtPoint thePointsOfACube[8];
- RtBound bb;
-
-
- if (NXDrawingStatus == NX_DRAWING)
- { [self drawOriginStartingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
-
- N3D_CopyBound(*([self boundingBoxStartingAt:shutterOpenTime endingAt:shutterCloseTime]), bb);
- thePointsOfACube[0][0] = bb[0];
- thePointsOfACube[0][1] = bb[3];
- thePointsOfACube[0][2] = bb[5];
-
- thePointsOfACube[1][0] = bb[1];
- thePointsOfACube[1][1] = bb[3];
- thePointsOfACube[1][2] = bb[5];
-
- thePointsOfACube[2][0] = bb[1];
- thePointsOfACube[2][1] = bb[3];
- thePointsOfACube[2][2] = bb[4];
-
- thePointsOfACube[3][0] = bb[0];
- thePointsOfACube[3][1] = bb[3];
- thePointsOfACube[3][2] = bb[4];
-
- thePointsOfACube[4][0] = bb[0];
- thePointsOfACube[4][1] = bb[2];
- thePointsOfACube[4][2] = bb[5];
-
- thePointsOfACube[5][0] = bb[1];
- thePointsOfACube[5][1] = bb[2];
- thePointsOfACube[5][2] = bb[5];
-
- thePointsOfACube[6][0] = bb[1];
- thePointsOfACube[6][1] = bb[2];
- thePointsOfACube[6][2] = bb[4];
-
- thePointsOfACube[7][0] = bb[0];
- thePointsOfACube[7][1] = bb[2];
- thePointsOfACube[7][2] = bb[4];
-
- RiPointsPolygons(nPolys, nVerts, verts, RI_P, thePointsOfACube, RI_NULL);
-
- // we now need to render our rib commands.
- // we need to do this so that our children shapes are transformed correctly
- // this is actually a bit weird, because the rib commands
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[ribCommandList objectAt:i] renderSelfAsBox:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
-
- return self;
- }
-
- - renderSelfAsBox:(N3DCamera *)camera
- {
- RtFloat shutterOpenTime = [(WW3DCamera *)camera shutterOpenTime],
- shutterCloseTime = [(WW3DCamera *)camera shutterCloseTime];
-
-
- return [self renderSelfAsBox:(WW3DCamera *)camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
-
-
- - preRenderSelf:(WW3DCamera *)camera startingAt:(RtFloat)shutterOpenTime endingAt:(RtFloat)shutterCloseTime
- {
- int i, howMany = [ribCommandList count];
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWRenderable>)[ribCommandList objectAt:i] preRenderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
- return self;
- }
-
-
- - preRenderSelf:(WW3DCamera *)camera
- {
- int i, howMany = [ribCommandList count];
- RtFloat shutterOpenTime = [camera shutterOpenTime],
- shutterCloseTime = [camera shutterCloseTime];
-
-
- for (i = 0; i < howMany; i++)
- { [(id <WWAnimatable>)[ribCommandList objectAt:i] preRenderSelf:camera startingAt:shutterOpenTime endingAt:shutterCloseTime];
- }
- return self;
- }
-
-
- - setShadingGroup:(const char *)newGroup
- {
- if (shadingGroup) { free(shadingGroup); }
- shadingGroup = NXCopyStringBuffer(newGroup);
- return self;
- }
-
- - setMaterialGroup:(const char *)newGroup
- {
- if (materialGroup) { free(materialGroup); }
- materialGroup = NXCopyStringBuffer(newGroup);
- return self;
- }
-
- - setGeometryGroup:(const char *)newGroup
- {
- if (geometryGroup) { free(geometryGroup); }
- geometryGroup = NXCopyStringBuffer(newGroup);
- return self;
- }
-
-
- - ribCommands { return ribCommandList; }
- - appendRIBCommand:newRIBCommand
- {
- if ([newRIBCommand isKindOf:[EveCommand class]]) {
- hasEveCmd = YES;
- }
- [ribCommandList addObject:newRIBCommand];
- dirtyBoundingBox = YES;
- return self;
- }
-
- - setSelected:(BOOL)selectionFlag andDrawOrigin:(BOOL)drawOriginFlag
- { selected = selectionFlag;
- [self setDrawOrigin:drawOriginFlag];
- return self;
- }
-
- - setDrawOrigin:(BOOL)drawOriginFlag { drawOrigin = drawOriginFlag; return self; }
-
- - updateBases
- {
- int howManyPositions, i;
- BOOL foundIt;
- id cmd = nil;
-
-
- howManyPositions = [ribCommandList count];
- i = howManyPositions - 1;
- foundIt = NO;
- while (!foundIt && (i > 0))
- { cmd = [ribCommandList objectAt:i];
- if ([cmd respondsTo:@selector(uBasis)])
- { foundIt = YES;
- }
- else
- { i--;
- }
- }
-
- if (foundIt) // that's it; copy it from the last RIBBasis cmd
- { N3D_CopyMatrix(*([cmd uBasis]), uBasis);
- uBasisToken = [ancestor uBasisToken];
- uStep = [cmd uStep];
- N3D_CopyMatrix(*([cmd vBasis]), vBasis);
- vBasisToken = [ancestor vBasisToken];
- vStep = [cmd vStep];
- }
- else // not defined here; ask up the shape hierarchy
- { if ((ancestor) && (ancestor != self)) // get it from our ancestor
- { N3D_CopyMatrix(*([ancestor uBasis]), uBasis);
- uBasisToken = [ancestor uBasisToken];
- uStep = [ancestor uStep];
- N3D_CopyMatrix(*([ancestor vBasis]), vBasis);
- vBasisToken = [ancestor vBasisToken];
- vStep = [ancestor vStep];
- }
- else // we are the root; fill in bezier bases for both u and v
- { N3D_CopyMatrix(RiBezierBasis, uBasis);
- uBasisToken = RI_BEZIER;
- uStep = 3;
- N3D_CopyMatrix(RiBezierBasis, vBasis);
- vStep = 3;
- vBasisToken = RI_BEZIER;
- }
- }
-
- dirtyBases = NO;
- return self;
- }
-
-
- - (RtBound *)boundingBoxStartingAt:(RtFloat)intervalStart endingAt:(RtFloat)intervalEnd
- {
- if (!dirtyBoundingBox)
- { // okay, this means we haven't been sent any messages that would have invalidated the boundingBox cache
- // now check intervals...
- if ((intervalStart == bbIntervalStart) && (intervalEnd == bbIntervalEnd))
- { // cool! we can use the cached version!!
- return &boundingBox;
- }
- }
- // damn! have to recalculate it..
- [self calculateBoundingBoxStartingAt:intervalStart endingAt:intervalEnd];
- // don't forget to refill the cache
- bbIntervalStart = intervalStart;
- bbIntervalEnd = intervalEnd;
- dirtyBoundingBox = FALSE;
-
- // so what things might invalidate the cache? Basically if I get a
- // new child or an addition to my ribCommandList, the bounding box
- // is invalidated.
-
- return &boundingBox;
- }
-
- - (RtBasis *)uBasis { if (dirtyBases) { [self updateBases]; } return &uBasis; }
- - (RtToken)uBasisToken { if (dirtyBases) { [self updateBases]; } return uBasisToken; }
- - (RtInt)uStep { if (dirtyBases) { [self updateBases]; } return uStep; }
- - (RtBasis *)vBasis { if (dirtyBases) { [self updateBases]; } return &vBasis; }
- - (RtToken)vBasisToken { if (dirtyBases) { [self updateBases]; } return vBasisToken; }
- - (RtInt)vStep { if (dirtyBases) { [self updateBases]; } return vStep; }
-
- - setTransformMatrix:(RtMatrix)tm
- {
- //[self logTransformWithMsg:"setTransformMatrix:(RtMatrix)tm BEFORE"];
- [super setTransformMatrix:tm];
- //[self logTransformWithMsg:"setTransformMatrix:(RtMatrix)tm AFTER"];
- return self;
- }
-
- - concatTransformMatrix:(RtMatrix)ctm premultiply:(BOOL)flag
- {
- //[self logTransformWithMsg:"concatTransformMatrix:(RtMatrix)ctm premultiply:(BOOL)flag BEFORE"];
- [super concatTransformMatrix:ctm premultiply:flag];
- //[self logTransformWithMsg:"concatTransformMatrix:(RtMatrix)ctm premultiply:(BOOL)flag AFTER"];
- return self;
- }
-
- - rotateAngle:(float)ang axis:(RtPoint)anAxis
- {
- //[self logTransformWithMsg:"rotateAngle:(float)ang axis:(RtPoint)anAxis BEFORE"];
- [super rotateAngle:ang axis:anAxis];
- //[self logTransformWithMsg:"rotateAngle:(float)ang axis:(RtPoint)anAxis AFTER"];
- return self;
- }
-
- - preRotateAngle:(float)ang axis:(RtPoint)anAxis
- {
- //[self logTransformWithMsg:"preRotateAngle:(float)ang axis:(RtPoint)anAxis BEFORE"];
- [super preRotateAngle:ang axis:anAxis];
- //[self logTransformWithMsg:"preRotateAngle:(float)ang axis:(RtPoint)anAxis AFTER"];
- return self;
- }
-
- - scale:(float)sx :(float)sy :(float)sz
- {
- //[self logTransformWithMsg:"scale:(float)sx :(float)sy :(float)sz BEFORE"];
- [super scale:sx :sy :sz];
- //[self logTransformWithMsg:"scale:(float)sx :(float)sy :(float)sz AFTER"];
- return self;
- }
-
- - preScale:(float)sx :(float)sy :(float)sz
- {
- //[self logTransformWithMsg:"preScale:(float)sx :(float)sy :(float)sz BEFORE"];
- [super preScale:sx :sy :sz];
- //[self logTransformWithMsg:"preScale:(float)sx :(float)sy :(float)sz AFTER"];
- return self;
- }
-
- - scaleUniformly:(float)s
- {
- //[self logTransformWithMsg:"scaleUniformly:(float)s BEFORE"];
- [super scaleUniformly:s];
- //[self logTransformWithMsg:"scaleUniformly:(float)s AFTER"];
- return self;
- }
-
- - preScaleUniformly:(float)s
- {
- //[self logTransformWithMsg:"preScaleUniformly:(float)s BEFORE"];
- [super preScaleUniformly:s];
- //[self logTransformWithMsg:"preScaleUniformly:(float)s AFTER"];
- return self;
- }
-
- - translate:(float)tx :(float)ty :(float)tz
- {
- //[self logTransformWithMsg:"translate:(float)tx :(float)ty :(float)tz BEFORE"];
- [super translate:tx :ty :tz];
- //[self logTransformWithMsg:"translate:(float)tx :(float)ty :(float)tz AFTER"];
- return self;
- }
-
- - preTranslate:(float)tx :(float)ty :(float)tz
- {
- //[self logTransformWithMsg:"preTranslate:(float)tx :(float)ty :(float)tz BEFORE"];
- [super preTranslate:tx :ty :tz];
- //[self logTransformWithMsg:"preTranslate:(float)tx :(float)ty :(float)tz AFTER"];
- return self;
- }
-
-
- - logTransformWithMsg:(const char *)aMsg
- {
- if (aMsg)
- { NXLogError("WW3DShape %s transform matrix: %s\n", [self shapeName], aMsg);
- }
- else
- { NXLogError("WW3DShape %s transform matrix\n", [self shapeName]);
- }
- NXLogError("\t%f\t%f\t%f\t%f\n", transform[0][0], transform[0][1], transform[0][2], transform[0][3]);
- NXLogError("\t%f\t%f\t%f\t%f\n", transform[1][0], transform[1][1], transform[1][2], transform[1][3]);
- NXLogError("\t%f\t%f\t%f\t%f\n", transform[2][0], transform[2][1], transform[2][2], transform[2][3]);
- NXLogError("\t%f\t%f\t%f\t%f\n", transform[3][0], transform[3][1], transform[3][2], transform[3][3]);
- return self;
- }
-
- - addChild:newChild
- {
- id oldDescendant = nil,
- oldDescendantList = [[List alloc] init],
- parentShape = self;
-
-
- // I think I want to unlink the old descendant, link the child in as
- // the new one, and then make the oldDescendant the peer of the child.
- oldDescendant = [parentShape descendant];
- if (oldDescendant)
- { while (oldDescendant)
- { [oldDescendantList addObject:oldDescendant];
- [oldDescendant unlink];
- oldDescendant = [parentShape descendant];
- }
- }
- [parentShape linkDescendant:newChild];
- if (oldDescendantList)
- { oldDescendant = [oldDescendantList objectAt:0];
- while (oldDescendant)
- { [newChild linkPeer:oldDescendant];
- [oldDescendantList removeObjectAt:0];
- oldDescendant = [oldDescendantList objectAt:0];
- }
- [oldDescendantList free];
- }
- dirtyBoundingBox = YES;
-
- return self;
- }
-
-
- - siblings
- {
- id currentPeer;
-
-
- // Really should cache this by trapping all the hierarchy frobbing and
- // having a dirty bit set. For right now, recalculate each time.
-
- [siblingList empty];
-
- if (self != [self firstPeer])
- { [siblingList addObject:[self firstPeer]];
- currentPeer = [self firstPeer];
-
- while ([currentPeer nextPeer])
- { [siblingList addObject:[currentPeer nextPeer]];
- currentPeer = [currentPeer nextPeer];
- }
- }
-
- return siblingList;
- }
-
- - children
- {
- id currentPeer;
-
-
- // Really should cache this by trapping all the hierarchy frobbing and
- // having a dirty bit set. For right now, recalculate each time.
-
- [childList empty];
-
- [childList addObject:[self descendant]];
- currentPeer = descendant;
- // note that the descendant is the firstPeer of it's siblings...
- while ([currentPeer nextPeer])
- { [childList addObject:[currentPeer nextPeer]];
- currentPeer = [currentPeer nextPeer];
- }
-
- return childList;
- }
-
- - parent { return ancestor; }
-
- - (unsigned short)pathSeparator { return pathSeparator; }
- - setPathSeparator:(unsigned short)newSeparator { pathSeparator = newSeparator; return self; }
-
-
- - getChildGivenPath:(const char *)path
- {
- char *part = (char *)path;
- int cnt, howMany, i;
- id ret;
-
-
- // the string looks something like "/foo/bar/zap/zow"
- // if the whole string is "/", return yourself
- // if the first part doesn't match your name, return nil.
- // if what's left after the first part is nil, return self;
- // if you're still here, send the message to each child until it doesn't return nil.
- // if you get through all your children and it still returns nil, return nil.
-
- if ((strlen(path) == 1) && ((unsigned short)(*part) == pathSeparator))
- { return self;
- }
-
- while (*part && ((unsigned short)(*part) != pathSeparator)) { part++; }
- // from "/foo/bar" to "/bar" or from "/foo" to ""
- cnt = part - (path + 1);
- if (!cnt) { return nil; } // catch the "/foo" to "" case
-
- if (!strncmp((path+1), [self shapeName], cnt))
- { // the first part is my name
- if (!*part) { return self; }// if there isn't anything else, I'm who they're looking for
-
- // otherwise, send message to each child to see if it's them
- howMany = [childList count];
- i = 0;
- while (i < howMany)
- { ret = [[childList objectAt:i] getChildGivenPath:part];
- if (ret)
- { return ret;
- }
- i++;
- }
- }
- // that isn't my name at the beginning - this isn't for me or any of my kids
- return nil;
- }
-
- - (char *)getPath
- {
- char *path, pathSeparatorString[2];
- int cnt = 1,
- i;
- id theShape;
- List *myShapeList;
-
-
- myShapeList = [[List alloc] init];
- theShape = self;
- while (theShape)
- { cnt += 2 + strlen([theShape shapeName]);
- [myShapeList addObject:theShape];
- theShape = [theShape ancestor];
- }
-
- path = malloc(cnt);
- if (!path)
- { [myShapeList free];
- return NULL;
- }
-
- path[0] = '\0';
- sprintf(pathSeparatorString, "%c", pathSeparator);
- for (i = [myShapeList count] - 1; i >= 0; i--)
- { strcat(path, pathSeparatorString);
- strcat(path, [[myShapeList objectAt:i] shapeName]);
- }
-
- return path;
- }
-
- - getInitialTransformMatrix:(RtMatrix)aMatrix
- {
- N3D_CopyMatrix(N3DIdentityMatrix, aMatrix);
- return self;
- }
-
- - setSelectedColor:(RtColor)newColor
- { selectedColor[0] = newColor[0];
- selectedColor[1] = newColor[1];
- selectedColor[2] = newColor[2];
-
- return self;
- }
- - (RtColor *)selectedColor { return &selectedColor; }
-
- - setUnselectedColor:(RtColor)newColor
- { unselectedColor[0] = newColor[0];
- unselectedColor[1] = newColor[1];
- unselectedColor[2] = newColor[2];
-
- return self;
- }
- - (RtColor *)unselectedColor { return &unselectedColor; }
-
-
- // WavesWorld archiving:
- // writeEve:(NXStream *)stream
- // writeScene:(NXStream *)stream
-
- - (BOOL)matricesAreEqual:(RtMatrix)m1 :(RtMatrix)m2
- {
- if (m1[0][0] != m2[0][0]) { return NO; }
- if (m1[0][1] != m2[0][1]) { return NO; }
- if (m1[0][2] != m2[0][2]) { return NO; }
- if (m1[0][3] != m2[0][3]) { return NO; }
-
- if (m1[1][0] != m2[1][0]) { return NO; }
- if (m1[1][1] != m2[1][1]) { return NO; }
- if (m1[1][2] != m2[1][2]) { return NO; }
- if (m1[1][3] != m2[1][3]) { return NO; }
-
- if (m1[2][0] != m2[2][0]) { return NO; }
- if (m1[2][1] != m2[2][1]) { return NO; }
- if (m1[2][2] != m2[2][2]) { return NO; }
- if (m1[2][3] != m2[2][3]) { return NO; }
-
- if (m1[3][0] != m2[3][0]) { return NO; }
- if (m1[3][1] != m2[3][1]) { return NO; }
- if (m1[3][2] != m2[3][2]) { return NO; }
- if (m1[3][3] != m2[3][3]) { return NO; }
-
- return YES;
- }
-
- - (BOOL)isIdentityMatrix:(RtMatrix)m { return [self matricesAreEqual:(RtFloat (*)[4])N3DIdentityMatrix :m]; }
-
- - writeEve:(NXStream *)stream atTabLevel:(int)tab
- {
- RtMatrix aMatrix;
- int i, howManySpaces, howMany = [ribCommandList count];
- id aCmd;
-
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "startShape {%s} ", [self shapeName]);
- [self getTransformMatrix:aMatrix];
- if ([self isIdentityMatrix:aMatrix])
- { NXPrintf(stream, ";\n");
- }
- else // need to add the transformation matrix, since it's not the identity matrix...
- { NXPrintf(stream, "{");
- NXPrintf(stream, "%f %f %f %f ", aMatrix[0][0], aMatrix[0][1], aMatrix[0][2], aMatrix[0][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
- // it would be nice if we put these on separate lines, but line up...
- // how far in do we need to go? well, first we need to tab the right amount, and then
- // move over "startShape " + strlen([self shapeName]) + "{"....
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- howManySpaces = strlen("startShape ") + strlen([self shapeName]) + strlen(" {");
-
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f ", aMatrix[1][0], aMatrix[1][1], aMatrix[1][2], aMatrix[1][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f ", aMatrix[2][0], aMatrix[2][1], aMatrix[2][2], aMatrix[2][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f};\n", aMatrix[3][0], aMatrix[3][1], aMatrix[3][2], aMatrix[3][3]);
- NXPrintf(stream, "\n");
- }
- // WAVE!!! Need to write out the rest of my shaders here!!!
- if (surfaceShader)
- { [surfaceShader writeEve:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
- if (displacementShader)
- { [displacementShader writeEve:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
-
- // okay, now tell all my rib commands to write themselves out...
- for (i = 0; i < howMany; i++)
- { aCmd = [ribCommandList objectAt:i];
- [aCmd writeEve:stream atTabLevel:(tab+1)];
- NXPrintf(stream, "\n");
- }
-
- // now tell my descendant to writeEve: itself...
- if (descendant) // don't put an extra new-line out if I have no descendant...
- { [descendant writeEve:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "endShape\n");
-
- // now tell my nextPeer to writeEve: itself...
- [nextPeer writeEve:stream atTabLevel:tab];
-
- return self;
- }
-
- - writeScene:(NXStream *)stream atTabLevel:(int)tab
- {
- RtMatrix aMatrix;
- int i, howManySpaces, howMany = [ribCommandList count];
- id aCmd;
-
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "startShape {%s} ", [self shapeName]);
- [self getTransformMatrix:aMatrix];
- if ([self isIdentityMatrix:aMatrix])
- { NXPrintf(stream, ";\n");
- }
- else // need to add the transformation matrix, since it's not the identity matrix...
- { NXPrintf(stream, "{");
- NXPrintf(stream, "%f %f %f %f ", aMatrix[0][0], aMatrix[0][1], aMatrix[0][2], aMatrix[0][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
- // it would be nice if we put these on separate lines, but line up...
- // how far in do we need to go? well, first we need to tab the right amount, and then
- // move over "startShape " + strlen([self shapeName]) + "{"....
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- howManySpaces = strlen("startShape ") + strlen([self shapeName]) + strlen(" {");
-
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f ", aMatrix[1][0], aMatrix[1][1], aMatrix[1][2], aMatrix[1][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f ", aMatrix[2][0], aMatrix[2][1], aMatrix[2][2], aMatrix[2][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f};\n", aMatrix[3][0], aMatrix[3][1], aMatrix[3][2], aMatrix[3][3]);
- NXPrintf(stream, "\n");
- }
- // WAVE!!! Need to write out the rest of my shaders here!!!
- if (surfaceShader)
- { [surfaceShader writeScene:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
- if (displacementShader)
- { [displacementShader writeScene:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
-
- // okay, now tell all my rib commands to write themselves out...
- for (i = 0; i < howMany; i++)
- { aCmd = [ribCommandList objectAt:i];
- [aCmd writeScene:stream atTabLevel:(tab+1)];
- NXPrintf(stream, "\n");
- }
-
- // now tell my descendant to writeScene: itself...
- if (descendant) // don't put an extra new-line out if I have no descendant...
- { [descendant writeScene:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "endShape\n");
-
- // now tell my nextPeer to writeScene: itself...
- [nextPeer writeScene:stream atTabLevel:tab];
-
- return self;
- }
-
-
- - write3DTextScene:(NXStream *)stream atTabLevel:(int)tab index:(int)index time:(float)time until:(float)lastTime
- {
- RtMatrix aMatrix;
- int i,
- howManySpaces, howMany = [ribCommandList count];
- id aCmd;
-
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
-
- NXPrintf(stream, "set __text__(colorWW3DShape) {1 1 1}\n");
-
- NXPrintf(stream, "startShape WW3DShape; EveCmd {Color $__text__(colorWW3DShape)}; ");
- // need tab
- // need index (position in current list)
- NXPrintf(stream,
- "EveCmd {Translate [expr { %d * $__text__(tabLength)}] [expr {$__text__(spacingFactor) * %d * $__text__(spacing) * $__text__(fontSize)}] 0 };\n",
- tab, index);
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, " EveCmd {WW3DText $__text__(fontName) $__text__(fontSize) {");
- NXPrintf(stream, "startShape %s ", [self shapeName]);
- [self getTransformMatrix:aMatrix];
- if ([self isIdentityMatrix:aMatrix])
- { NXPrintf(stream, " } left;\n");
- }
- else // need to add the transformation matrix, since it's not the identity matrix...
- { NXPrintf(stream, "{");
- NXPrintf(stream, "%f %f %f %f ", aMatrix[0][0], aMatrix[0][1], aMatrix[0][2], aMatrix[0][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
- // it would be nice if we put these on separate lines, but line up...
- // how far in do we need to go? well, first we need to tab the right amount, and then
- // move over "startShape " + strlen([self shapeName]) + "{"....
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- howManySpaces = strlen("startShape ") + strlen([self shapeName]) + strlen(" {");
-
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f ", aMatrix[1][0], aMatrix[1][1], aMatrix[1][2], aMatrix[1][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f ", aMatrix[2][0], aMatrix[2][1], aMatrix[2][2], aMatrix[2][3]);
- NXPrintf(stream, "\\\n"); // this is so we can have a new line that tcl won't see...
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- for (i = 0; i < howManySpaces; i++)
- { NXPrintf(stream, " ");
- }
- NXPrintf(stream, "%f %f %f %f}} left;\n", aMatrix[3][0], aMatrix[3][1], aMatrix[3][2], aMatrix[3][3]);
- NXPrintf(stream, "\n");
- }
- NXPrintf(stream, "}\n");
-
- index++;
- // okay, next object - it will be a child of this shape:
- if (surfaceShader)
- { [surfaceShader write3DTextScene:stream atTabLevel:(tab+1) index:index++ time:time until:lastTime];
- NXPrintf(stream, "\n");
- }
-
- // okay, now tell all my rib commands to write themselves out...
- for (i = 0; i < howMany; i++)
- { aCmd = [ribCommandList objectAt:i];
- [aCmd write3DTextScene:stream atTabLevel:(tab+1) index:index++ time:time until:lastTime];
- NXPrintf(stream, "\n");
- }
-
- // now tell my descendant to writeEve: itself...
- if (descendant) // don't put an extra new-line out if I have no descendant...
- { [descendant write3DTextScene:stream atTabLevel:(tab+1) index:index++ time:time until:lastTime];
- NXPrintf(stream, "\n");
- }
-
- // okay, now finish this text shape off by putting out the endShape
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "startShape endShape; ");
- // need tab
- // need index (position in current list)
- NXPrintf(stream,
- "EveCmd {Translate [expr { %d * $__text__(tabLength)}] [expr {$__text__(spacingFactor) * %d * $__text__(spacing) * $__text__(fontSize)}] 0 };\n",
- tab, index);
- NXPrintf(stream, " EveCmd {WW3DText $__text__(fontName) $__text__(fontSize) {");
- NXPrintf(stream, "endShape");
- NXPrintf(stream, "} left;}\n");
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "endShape;\n");
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "endShape;\n"); // okay, end off the WW3DShape
-
- // now tell my nextPeer to writeEve: itself...
- [nextPeer write3DTextScene:stream atTabLevel:(tab+1) index:index time:time until:lastTime];
-
- return self;
- }
-
-
- - writeInventorAtTime:(float)currentTime to:(NXStream *)stream atTabLevel:(int)tab
- {
- RtMatrix aMatrix;
- int i, newTab, howMany = [ribCommandList count];
- id aCmd;
-
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "# startShape {%s}\n", [self shapeName]);
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "DEF \"%s\" Separator {\n", [self shapeName]);
- [self getTransformMatrix:aMatrix];
- if (![self isIdentityMatrix:aMatrix])
- {
-
- for (i = 0; i < (tab+1); i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "MatrixTransform {\n");
- for (i = 0; i < (tab+2); i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "matrix %f %f %f %f\n", aMatrix[0][0], aMatrix[0][1], aMatrix[0][2], aMatrix[0][3]);
- for (i = 0; i < (tab+2); i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, " %f %f %f %f\n", aMatrix[1][0], aMatrix[1][1], aMatrix[1][2], aMatrix[1][3]);
- for (i = 0; i < (tab+2); i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, " %f %f %f %f\n", aMatrix[2][0], aMatrix[2][1], aMatrix[2][2], aMatrix[2][3]);
- for (i = 0; i < (tab+2); i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, " %f %f %f %f\n", aMatrix[3][0], aMatrix[3][1], aMatrix[3][2], aMatrix[3][3]);
- for (i = 0; i < (tab+1); i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "}\n");
- }
- // WAVE!!! Need to write out the rest of my shaders here!!!
- if (surfaceShader)
- { [surfaceShader writeInventorAtTime:currentTime to:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
- if (displacementShader)
- { [displacementShader writeInventorAtTime:currentTime to:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
-
- // okay, now tell all my rib commands to write themselves out...
- newTab = tab + 1;
- for (i = 0; i < howMany; i++)
- { aCmd = [ribCommandList objectAt:i];
- if (![aCmd isMootStartingAt:currentTime endingAt:currentTime])
- { if ([aCmd popsCTM])
- { newTab--;
- }
- [aCmd writeInventorAtTime:currentTime to:stream atTabLevel:newTab];
- if ([aCmd pushesCTM])
- { newTab++;
- }
- NXPrintf(stream, "\n");
- }
- }
-
- // now tell my descendant to writeInventor: itself...
- if (descendant) // don't put an extra new-line out if I have no descendant...
- { [descendant writeInventorAtTime:currentTime to:stream atTabLevel:(tab + 1)];
- NXPrintf(stream, "\n");
- }
-
- for (i = 0; i < tab; i++)
- { NXPrintf(stream, "\t");
- }
- NXPrintf(stream, "}\n");
-
- // now tell my nextPeer to writeInventor: itself...
- [nextPeer writeInventorAtTime:currentTime to:stream atTabLevel:tab];
-
- return self;
- }
-
-
- // NeXTSTEP archiving:
- #define typeVectorVersion1 "@S***[3f][3f][3f]f[3f]f[3f]f@"
- #define typeValuesVersion1 &ribCommandList, &pathSeparator, \
- &shadingGroup, &materialGroup, &geometryGroup, \
- &selectedColor, &unselectedColor, \
- &xColor, &xExtent, \
- &yColor, &yExtent, \
- &zColor, &zExtent, \
- &interp
-
- #define typeVector "@S***fff@@"
- #define typeValues &ribCommandList, &pathSeparator, \
- &shadingGroup, &materialGroup, &geometryGroup, \
- &xExtent, &yExtent, &zExtent, \
- &interp, &sceneClock
-
-
- - read:(NXTypedStream *)stream
- {
- int version;
-
- [super read:stream];
-
- NX_DURING
- version = NXTypedStreamClassVersion(stream, "WW3DShape");
- if (version == 0) NXReadTypes(stream, "i", &version), version = 1;
- if (version == 1) {
- NXReadTypes(stream, typeVectorVersion1, typeValuesVersion1);
- sceneClock = nil;
- NXLogError("yikes! no sceneClock was archived with this shape...");
- }
- if (version == 2) {
- NXReadTypes(stream, typeVector, typeValues);
- NXReadArray(stream, "f", 3, selectedColor);
- NXReadArray(stream, "f", 3, unselectedColor);
- NXReadArray(stream, "f", 3, xColor);
- NXReadArray(stream, "f", 3, yColor);
- NXReadArray(stream, "f", 3, zColor);
- }
- NX_HANDLER
- NXLogError("in read: %s, exception [%d] raised.\n", [[self class] name], NXLocalHandler.code);
- return nil;
- NX_ENDHANDLER
-
- return self;
- }
-
-
- - write:(NXTypedStream *)stream
- {
- [super write:stream];
- NXWriteTypes(stream, typeVector, typeValues);
- NXWriteArray(stream, "f", 3, selectedColor);
- NXWriteArray(stream, "f", 3, unselectedColor);
- NXWriteArray(stream, "f", 3, xColor);
- NXWriteArray(stream, "f", 3, yColor);
- NXWriteArray(stream, "f", 3, zColor);
- return self;
- }
-
- // boy, this is dumb... This is to get around the stupid warnings from the compiler - ask wave for details
- - class { return [super class]; }
-
- @end
-